package com.dkts.oil.converter;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dkts.oil.util.*;
import com.dkts.oil.util.gis.GpsFormat;
import com.dkts.oil.util.gis.GpsPoint;
import com.dkts.oil.web.vo.response.subReq.OilStorageAddress;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.geojson.GeoJsonReader;
import org.locationtech.jts.io.geojson.GeoJsonWriter;
import org.locationtech.jts.operation.buffer.BufferOp;
import org.locationtech.jts.operation.union.CascadedPolygonUnion;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class GeometryConverter {

   public static GeometryFactory locationtechGeometryFactory = new GeometryFactory();


    public static Geometry convert(String geometryWkt) throws Exception {
        // 用新 GeometryFactory 读取 WKT
        org.locationtech.jts.io.WKTReader wktReader = new org.locationtech.jts.io.WKTReader(locationtechGeometryFactory);
        return wktReader.read(geometryWkt);
    }

    public static String getGeoJsonResult(List<Geometry> geometryList) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "FeatureCollection");
        jsonObject.put("name", "Polygon-" + DateUtils.getNewDateSs());
        // 转换为 JSON 输出
        JSONArray outputArray = new JSONArray();

        for (Geometry geometry : geometryList) {
            JSONObject polygonJsonObject = new JSONObject();
            polygonJsonObject.put("type", "Polygon");

            org.locationtech.jts.geom.Polygon poly = (org.locationtech.jts.geom.Polygon) geometry;
            JSONArray outerArray = new JSONArray();
            JSONArray innerArray = new JSONArray();
            for (org.locationtech.jts.geom.Coordinate coord : poly.getCoordinates()) {
                JSONArray point = new JSONArray();
                point.add(coord.x);
                point.add(coord.y);
                innerArray.add(point);
            }
            outerArray.add(innerArray);
            polygonJsonObject.put("coordinates", outerArray);
            JSONObject geometryJson = new JSONObject();
            geometryJson.put("geometry", polygonJsonObject);
            geometryJson.put("type", "Feature");
            geometryJson.put("properties", new JSONObject());

            outputArray.add(geometryJson);
        }

        jsonObject.put("features", outputArray);
        return jsonObject.toJSONString();
    }

    public static String getGeoJsonResult(JSONObject jsonObjectGeo) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "FeatureCollection");
        jsonObject.put("name", "PolygonOne-" + DateUtils.getNewDateSs());
        JSONArray outputArray = new JSONArray();

        JSONObject polygonJsonObject = new JSONObject();
        polygonJsonObject.put("type", "Polygon");

        JSONArray temp = jsonObjectGeo.getJSONObject("geometry").getJSONArray("coordinates").getJSONArray(0);
        JSONArray outerArray = new JSONArray();
        JSONArray innerArray = new JSONArray();
        for (int i = 0; i < temp.size(); i++) {
            JSONArray coord = temp.getJSONArray(i);
            JSONArray point = new JSONArray();
            point.add(coord.getDouble(0));
            point.add(coord.getDouble(1));
            innerArray.add(point);
        }
        outerArray.add(innerArray);
        polygonJsonObject.put("coordinates", outerArray);
        JSONObject geometryJson = new JSONObject();
        geometryJson.put("geometry", polygonJsonObject);
        geometryJson.put("type", "Feature");
        jsonObjectGeo.remove("geometry");
        geometryJson.put("properties", jsonObjectGeo);
        outputArray.add(geometryJson);

        jsonObject.put("features", outputArray);
        return jsonObject.toJSONString();
    }

    public static String geometryToGeoJson(Geometry geometry) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "FeatureCollection");
        jsonObject.put("name", "Polygon-" + DateUtils.getNewDateSs());
        // 转换为 JSON 输出
        JSONArray outputArray = new JSONArray();


        JSONObject polygonJsonObject = new JSONObject();
        polygonJsonObject.put("type", "Polygon");

        org.locationtech.jts.geom.Polygon poly = (org.locationtech.jts.geom.Polygon) geometry;
        JSONArray outerArray = new JSONArray();
        JSONArray innerArray = new JSONArray();
        for (org.locationtech.jts.geom.Coordinate coord : poly.getCoordinates()) {
            JSONArray point = new JSONArray();
            point.add(coord.x);
            point.add(coord.y);
            innerArray.add(point);
        }
        outerArray.add(innerArray);
        polygonJsonObject.put("coordinates", outerArray);
        JSONObject geometryJson = new JSONObject();
        geometryJson.put("geometry", polygonJsonObject);
        geometryJson.put("type", "Feature");
        geometryJson.put("properties", new JSONObject());

        outputArray.add(geometryJson);

        jsonObject.put("features", outputArray);
        return jsonObject.toJSONString();
    }

    public static Geometry dataDrawPolygon(JSONObject jsonObjectData) {
        JSONObject geometry = jsonObjectData.getJSONObject("geometry");
        String type=geometry.getString("type");
        if("MultiPolygon".equals(type)){
            return convertMultiPolygon(jsonObjectData);
        }else if("".equals(type)){
            return null;
        }

        JSONArray jsonArrayAll = geometry.getJSONArray("coordinates").getJSONArray(0);
        org.locationtech.jts.geom.Coordinate[] coordinates = new org.locationtech.jts.geom.Coordinate[jsonArrayAll.size()];
        for (int i = 0; i < jsonArrayAll.size(); i++) {
            JSONArray jsonArray1 = jsonArrayAll.getJSONArray(i);
            try{
            org.locationtech.jts.geom.Coordinate coordinate = new org.locationtech.jts.geom.Coordinate(jsonArray1.getDouble(0), jsonArray1.getDouble(1));
            coordinates[i] = coordinate;
            }catch (Exception e){
                System.out.println("error-->"+JSONObject.toJSONString(jsonObjectData));
                return null;
            }

        }
        try {
            return locationtechGeometryFactory.createPolygon(coordinates);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }

    public static Geometry convertMultiPolygon(JSONObject jsonObjectData)  {

//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("type", "FeatureCollection");
//        jsonObject.put("name", "MultiPolygon-" + DateUtils.getNewDateSs());
//        JSONArray jsonArray = new JSONArray();
//
//
//        jsonObjectData.put("type","Feature");
//        jsonObjectData.put("properties",new JSONObject());
//        jsonArray.add(jsonObjectData);
//        jsonObject.put("features", jsonArray);
//
//        GeoJSON geoJSON = GeoJSONFactory.create("{\n" +
//                "  \"type\": \"Feature\",\n" +
//                "  \"geometry\": {\n" +
//                "    \"type\": \"MultiPolygon\",\n" +
//                "    \"coordinates\": [[[[116.6251107421875,40.03798263020833],[116.62502469314242,40.03798259461806],[116.62502469314241,40.038110407552104],[116.6251107421875,40.038110477430564],[116.6251107421875,40.03798263020833]]]]\n" +
//                "  },\n" +
//                "  \"properties\": {\n" +
//                "    \"label\": \"1000003\",\n" +
//                "    \"id\": \"SCmQGJYB6oJ6tkeSHTcZ\",\n" +
//                "    \"floor\": 1,\n" +
//                "    \"layer\": \"北京\"\n" +
//                "  }\n" +
//                "}\n");
//
//        GeometryJSON gjson = new GeometryJSON();
//        Reader reader = new StringReader(geoJSON.toString());
//        try {
//            Geometry geometry = gjson.read(reader);
//            String  ret = geometry.toText();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

//        GeoJSONReader reader = new GeoJSONReader();
//        org.locationtech.jts.geom.Geometry geometry = reader.read(geoJSON);
//        return geometry;
        return null;
    }

    public static void main(String[] args) {
        String data="{\"geometry\":{\"coordinates\":[[[[116.6251107421875,40.03798263020833],[116.62502469314242,40.03798259461806],[116.62502469314241,40.038110407552104],[116.6251107421875,40.038110477430564],[116.6251107421875,40.03798263020833]]]],\"type\":\"MultiPolygon\"}}";
        JSONObject jsonObjectData = JSONObject.parseObject(data);

        Geometry geometry=convertMultiPolygon(jsonObjectData);
    }

    public static Polygon dataDrawVividsolutionsPolygon(JSONObject jsonObjectData) {
        JSONArray jsonArrayAll = jsonObjectData.getJSONObject("geometry").getJSONArray("coordinates").getJSONArray(0);
         Coordinate[] coordinates = new Coordinate[jsonArrayAll.size()];
        for (int i = 0; i < jsonArrayAll.size(); i++) {
            JSONArray jsonArray1 = jsonArrayAll.getJSONArray(i);
            Coordinate coordinate = new Coordinate(jsonArray1.getDouble(0), jsonArray1.getDouble(1));
            coordinates[i] = coordinate;
        }
        Polygon polygon= locationtechGeometryFactory.createPolygon(coordinates);
        JSONObject properties = jsonObjectData.getJSONObject("properties");
        polygon.setUserData(properties);
        return polygon;
    }

    /**
     * 获取缓冲区域
     *
     * @param gmt  实体图
     * @param rd   缓冲去距离
     * @return
     */
    public static Geometry getBuff(Geometry gmt,  double rd) {
        BufferOp bufOp = new BufferOp(gmt);
        bufOp.setEndCapStyle(BufferOp.CAP_ROUND);
        bufOp.setQuadrantSegments(18);
        return GeometryPrecisionUtil.roundCoordinates(bufOp.getResultGeometry(radius(rd)),6);
    }

    /**
     * 获取缓冲区域
     *
     * @param gmt  实体图
     * @return
     */
    public static Geometry difference(Geometry gmt,  Geometry gmt2) {
        try {
            return GeometryPrecisionUtil.roundCoordinates(gmt.symDifference(gmt2), 6);
        }catch (Exception e){
            return locationtechGeometryFactory.createPolygon();
        }
    }

    public static Geometry union(List<Geometry> list) {
        return GeometryPrecisionUtil.roundCoordinates(CascadedPolygonUnion.union(list),6);
    }

    public static double radius(double radius) {
        return radius / (2 * Math.PI * 6371004) * 360;
    }

    public static List<OilStorageAddress> oilStorage(double gridLength,List<Geometry> list,int row,String type,Geometry planGeometry2) throws Exception {
        Geometry geometry01=union(list);
        int count = geometry01.getNumGeometries();
        List<OilStorageAddress> oilStorageAddresses = new ArrayList<>();
        for (int i = 0; i < count; i++){
            Geometry geometry =geometry01.getGeometryN(i);
            OilStorageAddress oilStorageAddress=new OilStorageAddress();
            oilStorageAddress.setBoundWkt(geometry.toText());
            double[] doubles=GeoAreaUtil.calculateAreaInSquareMeters(geometry);
            oilStorageAddress.setArea(doubles[0]);
            oilStorageAddress.setPerimeter(doubles[1]);
            oilStorageAddress.setIndex(i);


            double distance= TrackMileageUtil.distance(geometry.getCentroid().getY(),geometry.getCentroid().getX(),planGeometry2.getCentroid().getY(),planGeometry2.getCentroid().getX());
            oilStorageAddress.setCenterDistance(distance);
            oilStorageAddresses.add(oilStorageAddress);

//            WriterToFile.writerFileGeoJson("D:\\dkSpace\\油库规划\\temp\\推荐油库——"+type+"——"+i+".geojson",GeojsonUtil.geoToJsonByGeometry(geometry));
        }
        //按照面积最大距离最近排序
//        oilStorageAddresses.sort(
//                Comparator.comparing(OilStorageAddress::getArea, Comparator.nullsLast(Comparator.reverseOrder()))
//                        .thenComparing(OilStorageAddress::getCenterDistance, Comparator.nullsLast(Comparator.naturalOrder()))
//        );
        oilStorageAddresses.sort(
                Comparator.comparing(OilStorageAddress::getCenterDistance, Comparator.nullsLast(Comparator.naturalOrder()))
                        .thenComparing(OilStorageAddress::getArea, Comparator.nullsLast(Comparator.reverseOrder()))
        );

        List<OilStorageAddress> oilStorageAddresses1=oilStorageAddresses.subList(0,oilStorageAddresses.size()>row?row:oilStorageAddresses.size());
        List<Geometry> list1=new ArrayList<>();
        for (int i = 0; i < oilStorageAddresses1.size(); i++) {
//            Geometry geometry = list.get(oilStorageAddresses1.get(i).getIndex());
            Geometry geometry = geometry01.getGeometryN(oilStorageAddresses1.get(i).getIndex());
            list1.add(geometry);
        }
        WriterToFile.writerFileGeoJson("D:\\dkSpace\\油库规划\\temp\\推荐油库——"+type+"——地址.geojson",GeojsonUtil.toGeoJson(list1));
        return oilStorageAddresses1;
    }

    /**
     * 将 GeoJSON 字符串转换为 Geometry 对象
     *
     * @param geoJson GeoJSON 字符串
     * @return Geometry 对象
     * @throws ParseException 解析失败时抛出
     */
    public static Geometry geoJsonToGeometry(String geoJson) throws ParseException {
        GeoJsonReader reader = new GeoJsonReader(locationtechGeometryFactory);
        return reader.read(geoJson);
    }

    /**
     * 将 Geometry 对象转换为 GeoJSON 字符串
     *
     * @param geometry JTS Geometry 对象
     * @return GeoJSON 字符串
     */
    public static String geometryToGeoJsonByJts(Geometry geometry) {
        GeoJsonWriter writer = new GeoJsonWriter();
        writer.setEncodeCRS(false); // 关闭 CRS 输出，避免兼容性问题
        return writer.write(geometry);
    }


    public static Geometry transformGCJ02ToWGS84(Geometry geometry) {
        if (geometry == null || geometry.isEmpty()) {
            return geometry;
        }

        if (geometry instanceof Point) {
            return transformPoint((Point) geometry);
        } else if (geometry instanceof LineString) {
            return transformLineString((LineString) geometry);
        } else if (geometry instanceof Polygon) {
            return transformPolygon((Polygon) geometry);
        } else if (geometry instanceof MultiPolygon) {
            int num = geometry.getNumGeometries();
            Polygon[] polygons = new Polygon[num];
            for (int i = 0; i < num; i++) {
                polygons[i] = (Polygon) transformGCJ02ToWGS84(geometry.getGeometryN(i));
            }
            return locationtechGeometryFactory.createMultiPolygon(polygons);
        } else if (geometry instanceof MultiLineString) {
            int num = geometry.getNumGeometries();
            LineString[] lines = new LineString[num];
            for (int i = 0; i < num; i++) {
                lines[i] = (LineString) transformGCJ02ToWGS84(geometry.getGeometryN(i));
            }
            return locationtechGeometryFactory.createMultiLineString(lines);
        } else {
            // 默认返回 clone
            return (Geometry) geometry.clone();
        }
    }

    public static Geometry transformWGS84ToGCJ02(Geometry geometry) {
        if (geometry == null || geometry.isEmpty()) {
            return geometry;
        }

        if (geometry instanceof Point) {
            return wgs84ToGCJ02((Point) geometry);
        } else if (geometry instanceof LineString) {
            return wgs84ToGCJ02Line((LineString) geometry);
        } else if (geometry instanceof Polygon) {
            return wgs84ToGCJ02Polygon((Polygon) geometry);
        } else if (geometry instanceof MultiPolygon) {
            int num = geometry.getNumGeometries();
            Polygon[] polygons = new Polygon[num];
            for (int i = 0; i < num; i++) {
                polygons[i] = (Polygon) transformWGS84ToGCJ02(geometry.getGeometryN(i));
            }
            return locationtechGeometryFactory.createMultiPolygon(polygons);
        } else if (geometry instanceof MultiLineString) {
            int num = geometry.getNumGeometries();
            LineString[] lines = new LineString[num];
            for (int i = 0; i < num; i++) {
                lines[i] = (LineString) transformWGS84ToGCJ02(geometry.getGeometryN(i));
            }
            return locationtechGeometryFactory.createMultiLineString(lines);
        } else {
            // 默认返回 clone
            return (Geometry) geometry.clone();
        }
    }

    private static Point transformPoint(Point point) {
        Coordinate coord = point.getCoordinate();
        GpsPoint gpsPoint = GpsFormat.gcj02ToWgs84(coord.x, coord.y); // 注意：lat, lon
        return locationtechGeometryFactory.createPoint(new Coordinate(gpsPoint.getLng(), gpsPoint.getLat()));
    }

    private static LineString transformLineString(LineString line) {
        Coordinate[] coords = line.getCoordinates();
        for (int i = 0; i < coords.length; i++) {
            GpsPoint wgs84 = GpsFormat.gcj02ToWgs84(coords[i].x, coords[i].y);
            coords[i] = new Coordinate(wgs84.getLng(), wgs84.getLat());
        }
        return locationtechGeometryFactory.createLineString(coords);
    }

    private static Polygon transformPolygon(Polygon polygon) {
        LinearRing shell = locationtechGeometryFactory.createLinearRing(
                transformCoordinates(polygon.getExteriorRing().getCoordinates()));
        LinearRing[] holes = new LinearRing[polygon.getNumInteriorRing()];
        for (int i = 0; i < holes.length; i++) {
            holes[i] = locationtechGeometryFactory.createLinearRing(
                    transformCoordinates(polygon.getInteriorRingN(i).getCoordinates()));
        }
        return locationtechGeometryFactory.createPolygon(shell, holes);
    }

    private static Coordinate[] transformCoordinates(Coordinate[] coords) {
        Coordinate[] result = new Coordinate[coords.length];
        for (int i = 0; i < coords.length; i++) {
            GpsPoint wgs84 = GpsFormat.gcj02ToWgs84(coords[i].x, coords[i].y);
            result[i] = new Coordinate(wgs84.getLng(), wgs84.getLat());
        }
        return result;
    }





    private static Point wgs84ToGCJ02(Point point) {
        Coordinate coord = point.getCoordinate();
        GpsPoint gpsPoint = GpsFormat.wgs84ToGcj02(coord.x, coord.y); // 注意：lat, lon
        return locationtechGeometryFactory.createPoint(new Coordinate(gpsPoint.getLng(), gpsPoint.getLat()));
    }

    private static LineString wgs84ToGCJ02Line(LineString line) {
        Coordinate[] coords = line.getCoordinates();
        for (int i = 0; i < coords.length; i++) {
            GpsPoint wgs84 = GpsFormat.wgs84ToGcj02(coords[i].x, coords[i].y);
            coords[i] = new Coordinate(wgs84.getLng(), wgs84.getLat());
        }
        return locationtechGeometryFactory.createLineString(coords);
    }

    private static Polygon wgs84ToGCJ02Polygon(Polygon polygon) {
        LinearRing shell = locationtechGeometryFactory.createLinearRing(
                wgs84ToGCJ02Coordinates(polygon.getExteriorRing().getCoordinates()));
        LinearRing[] holes = new LinearRing[polygon.getNumInteriorRing()];
        for (int i = 0; i < holes.length; i++) {
            holes[i] = locationtechGeometryFactory.createLinearRing(
                    wgs84ToGCJ02Coordinates(polygon.getInteriorRingN(i).getCoordinates()));
        }
        return locationtechGeometryFactory.createPolygon(shell, holes);
    }

    private static Coordinate[] wgs84ToGCJ02Coordinates(Coordinate[] coords) {
        Coordinate[] result = new Coordinate[coords.length];
        for (int i = 0; i < coords.length; i++) {
            GpsPoint wgs84 = GpsFormat.wgs84ToGcj02(coords[i].x, coords[i].y);
            result[i] = new Coordinate(wgs84.getLng(), wgs84.getLat());
        }
        return result;
    }
}

